﻿using System;
using System.Linq;
using EInfrastructure.Core.Config.Entities.Configuration;
using EInfrastructure.Core.Config.Entities.Enumerations;
using EInfrastructure.Core.Config.Entities.Extensions;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;

namespace EInfrastructure.Core.EFCore.SqlServer
{
    /// <summary>
    /// DbContext工厂
    /// </summary>
    public interface IDbContextFactory<TDbContext> where TDbContext : DbContext
    {
        /// <summary>
        /// 得到上下文
        /// </summary>
        /// <param name="dbOptionType"></param>
        /// <returns></returns>
        DbContext GetDbContext(DbOptionType dbOptionType);
    }

    /// <summary>
    ///
    /// </summary>
    public class DbContextFactory<TDbContext> : IDbContextFactory<TDbContext> where TDbContext : DbContext
    {
        private readonly DbContextConfigOptions _dbContextConfigOption;

        /// <summary>
        ///
        /// </summary>
        /// <param name="contextConfigs"></param>
        public DbContextFactory(DbContextConfigs contextConfigs)
        {
            if (contextConfigs.Configurations.Count == 1)
            {
                this._dbContextConfigOption = contextConfigs.Configurations.FirstOrDefault();
            }
            else
            {
                this._dbContextConfigOption =
                    contextConfigs.Configurations.FirstOrDefault(x => x.FullName == typeof(TDbContext).FullName);
            }
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="contextConfigs"></param>
        public DbContextFactory(IOptions<DbContextConfigs> contextConfigs) : this(contextConfigs.Value)
        {
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="dbOptionType"></param>
        /// <returns></returns>
        public DbContext GetDbContext(DbOptionType dbOptionType)
        {
            var callName = $"{typeof(TDbContext).FullName}_{dbOptionType}";
            DbContext dbContext = (DbContext) CallContext.GetData(callName);
            if (dbContext == null)
            {
                dbContext = Activator.CreateInstance(typeof(TDbContext), GetOptions(dbOptionType)) as DbContext;
                CallContext.SetData(callName, dbContext);
            }

            return dbContext;
        }

        /// <summary>
        /// 获取DbContext的Options
        /// </summary>
        /// <param name="dbOptionType"></param>
        /// <returns></returns>
        private DbContextOptions<TDbContext> GetOptions(DbOptionType dbOptionType)
        {
            //随机选择读数据库节点
            var optionsBuilder = new DbContextOptionsBuilder<TDbContext>();
            var connection = this._dbContextConfigOption.GetConnectionString(dbOptionType);
            optionsBuilder.UseSqlServer(connection);
            return optionsBuilder.Options;
        }
    }
}
